home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / agrep / main.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  36KB  |  1,037 lines

  1. /* Copyright (c) 1991 Sun Wu and Udi Manber.  All Rights Reserved. */
  2. #include "agrep.h"
  3. #include "checkfile.h"
  4.  
  5. unsigned Mask[MAXSYM];
  6. unsigned Init1, NO_ERR_MASK, Init[MaxError];
  7. unsigned Bit[WORD+1];
  8. CHAR buffer[BlockSize+Maxline+1];
  9. unsigned Next[MaxNext], Next1[MaxNext];
  10. unsigned wildmask, endposition, D_endpos; 
  11. int  REGEX, RE_ERR, FNAME, WHOLELINE, SIMPLEPATTERN;
  12. int  COUNT, HEAD, TAIL, LINENUM, INVERSE, I, S, DD, AND, SGREP, JUMP; 
  13. int  Num_Pat, PSIZE, num_of_matched, SILENT, NOPROMPT, BESTMATCH, NOUPPER;
  14. int  NOMATCH, TRUNCATE, FIRST_IN_RE, FIRSTOUTPUT;
  15. int  WORDBOUND, DELIMITER, D_length;
  16. int  EATFIRST, OUTTAIL;
  17. int  FILEOUT;
  18. int  DNA = 0;
  19. int  APPROX = 0;
  20. int  PAT_FILE = 0;
  21. int  CONSTANT = 0;
  22. int total_line = 0; /* used in mgrep */
  23.                                      
  24. CHAR **Textfiles;     /* array of filenames to be searched */
  25. CHAR old_D_pat[MaxDelimit] = "\n";  /* to hold original D_pattern */
  26. CHAR CurrentFileName[MAXNAME]; 
  27. CHAR Progname[MAXNAME]; 
  28. CHAR D_pattern[MaxDelimit] = "\n; "; /* string which delimits records --
  29.                                         defaults to newline */   
  30. int  NOFILENAME = 0,  /* Boolean flag, set for -h option */
  31.      FILENAMEONLY = 0,/* Boolean flag, set for -l option */
  32.      Numfiles = 0;    /* indicates how many files in Textfiles */
  33. extern int init();
  34. int table[WORD][WORD];
  35.  
  36. initial_value()
  37. {
  38.    int i; 
  39.  
  40.    JUMP = REGEX = FNAME = BESTMATCH = NOPROMPT = NOUPPER = 0;
  41.    COUNT = LINENUM = WHOLELINE = SGREP = 0;
  42.    EATFIRST = INVERSE = AND = TRUNCATE = OUTTAIL = 0; 
  43.    FIRST_IN_RE = NOMATCH = FIRSTOUTPUT = ON;
  44.    I = DD = S = 1;
  45.    HEAD = TAIL = ON;
  46.    D_length = 2;
  47.    SILENT = Num_Pat = PSIZE = SIMPLEPATTERN = num_of_matched = 0 ;
  48.    WORDBOUND = DELIMITER = RE_ERR = 0;
  49.    Bit[WORD] = 1;
  50.    for (i = WORD - 1; i > 0  ; i--)  Bit[i] = Bit[i+1] << 1; 
  51.    for (i=0; i< MAXSYM; i++) Mask[i] = 0;
  52. }
  53.  
  54. compute_next(M, Next, Next1)
  55. int M; unsigned *Next, *Next1;
  56. {
  57.   int i, j=0, n,  k, temp;
  58.   int mid, pp;
  59.   int MM, base;
  60.   unsigned V[WORD];
  61.    
  62.   base = WORD - M;
  63.   temp = Bit[base]; Bit[base] = 0;
  64.   for (i=0; i<WORD; i++) V[i] = 0;
  65.   for (i=1; i<M; i++)
  66.   {  
  67.       j=0;
  68.       while (table[i][j] > 0 && j < 10) {
  69.             V[i] = V[i] | Bit[base + table[i][j++]];
  70.       }
  71.   }
  72.   Bit[base]=temp;
  73.   if(M <= SHORTREG)
  74.   {
  75.     k = exponen(M);
  76.     pp = 2*k;
  77.     for(i=k; i<pp ; i++)
  78.     {   n = i;
  79.         Next[i]= (k>>1);
  80.         for(j=M; j>=1; j--)
  81.         {
  82.            if(n & Bit[WORD]) Next[i] = Next[i] | V[j];
  83.            n = (n>>1);
  84.         }
  85.     }      
  86.     return;
  87.   }
  88.   if(M > MAXREG) fprintf(stderr, "%s: regular expression too long\n", Progname);
  89.   MM = M;
  90.   if(M & 1) M=M+1;
  91.   k = exponen(M/2);
  92.   pp = 2*k;
  93.   mid = MM/2;
  94.   for(i=k; i<pp ; i++)
  95.   {     n = i;
  96.         Next[i]= (Bit[base]>>1);
  97.         for(j=MM; j>mid ; j--)
  98.         {
  99.            if(n & Bit[WORD]) Next[i] = Next[i] | V[j-mid];
  100.            n = (n>>1);
  101.         }
  102.         n=i-k;
  103.         Next1[i-k] = 0;
  104.         for(j = 0; j<mid; j++)
  105.         {
  106.            if(n & Bit[WORD]) Next1[i-k] = Next1[i-k] | V[MM-j];
  107.            n = (n>>1);
  108.         }
  109.   }      
  110.   return;
  111. }
  112.   
  113. exponen(m)
  114. int m;
  115. { int i, ex;
  116.   ex= 1;
  117.   for (i=0; i<m; i++) ex= ex*2;
  118.   return(ex);
  119. }
  120.  
  121. re1(Text, M, D)
  122. int Text, M, D;
  123. {
  124.   register unsigned i, c, r0, r1, r2, r3, CMask, Newline, Init0, r_NO_ERR; 
  125.   register unsigned end;
  126.   register unsigned hh, LL=0, k;  /* Lower part */
  127.   int  FIRST_TIME=ON, num_read , j=0, base;
  128.   unsigned A[MaxRerror+1], B[MaxRerror+1];
  129.   unsigned Next[MaxNext], Next1[MaxNext];
  130.   CHAR buffer[BlockSize+Maxline+1];
  131.   int FIRST_LOOP = 1;
  132.    
  133.   r_NO_ERR = NO_ERR_MASK;
  134.   if(M > 30) {
  135.      fprintf(stderr, "%s: regular expression too long\n", Progname);
  136.      exit(2);
  137.   }
  138.   base = WORD - M;
  139.   hh = M/2;
  140.   for(i=WORD, j=0; j < hh ; i--, j++) LL = LL | Bit[i];
  141.   if(FIRST_IN_RE) compute_next(M, Next, Next1); 
  142.                                    /*SUN: try: change to memory allocation */
  143.   FIRST_IN_RE = 0;
  144.   Newline = '\n';
  145.   Init[0] = Bit[base];
  146.   if(HEAD) Init[0] = Init[0] | Bit[base+1];
  147.   for(i=1; i<= D; i++) Init[i] = Init[i-1] | Next[Init[i-1]>>hh] | Next1[Init[i-1]&LL];
  148.   Init1 = Init[0] | 1; 
  149.   Init0 = Init[0];
  150.   r2 = r3 = Init[0];
  151.   for(k=0; k<= D; k++) { A[k] = B[k] = Init[k]; }
  152.   if ( D == 0 )
  153.   {
  154.     while ((num_read = read(Text, buffer + Maxline, BlockSize)) > 0)
  155.     {
  156.       i=Maxline; end = num_read + Maxline;
  157.       if((num_read < BlockSize) && buffer[end-1] != '\n') buffer[end] = '\n';
  158.       if(FIRST_LOOP) {         /* if first time in the loop add a newline */
  159.         buffer[i-1] = '\n';  /* in front the  text.  */
  160.     i--;
  161.         FIRST_LOOP = 0;
  162.       }
  163.       while ( i < end )
  164.       {
  165.         c = buffer[i++];
  166.         CMask = Mask[c];
  167.         if(c != Newline)
  168.         {  if(CMask != 0) {  
  169.               r1 = Init1 & r3;
  170.               r2 = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) | r1;
  171.            }
  172.        else  {
  173.               r2 = r3 & Init1; 
  174.            }
  175.         }
  176.         else {  j++; 
  177.               r1 = Init1 & r3;            /* match against endofline */
  178.               r2 = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) | r1;
  179.               if(TAIL) r2 = (Next[r2>>hh] | Next1[r2&LL]) | r2;                                        /* epsilon move */
  180.               if(( r2 & 1 ) ^ INVERSE) {
  181.                    if(FILENAMEONLY) {
  182.                           num_of_matched++;
  183.                           printf("%s\n", CurrentFileName);
  184.                           return;
  185.                    } 
  186.                    r_output(buffer, i-1, end, j);
  187.               }
  188.               r3 = Init0;
  189.               r2 = (Next[r3>>hh] | Next1[r3&LL]) & CMask | Init0;  
  190.                                                /* match begin of line */
  191.         }
  192.         c = buffer[i++];
  193.         CMask = Mask[c];
  194.         if(c != Newline)
  195.         {  if(CMask != 0) {  
  196.               r1 = Init1 & r2;
  197.               r3 = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) | r1;
  198.            }
  199.        else   r3 = r2 & Init1; 
  200.         } /* if(NOT Newline) */
  201.         else {  j++;
  202.               r1 = Init1 & r2;            /* match against endofline */
  203.               r3 = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) | r1;
  204.               if(TAIL) r3 = ( Next[r3>>hh] | Next1[r3&LL] ) | r3; 
  205.                                            /* epsilon move */
  206.               if(( r3 & 1 ) ^ INVERSE) {
  207.                    if(FILENAMEONLY) {
  208.                           num_of_matched++;
  209.                           printf("%s\n", CurrentFileName);
  210.                           return;
  211.                    } 
  212.                    r_output(buffer, i-1, end, j);
  213.               }
  214.               r2 = Init0;
  215.               r3 = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) | Init0; 
  216.                    /* match begin of line */
  217.         }
  218.       } /* while i < end ... */
  219.       strncpy(buffer, buffer+num_read, Maxline);
  220.     } /* end while read()... */
  221.   return;
  222.   } /*  end if (D == 0) */
  223.   while ((num_read = read(Text, buffer + Maxline, BlockSize)) > 0)
  224.   {
  225.     i=Maxline; end = Maxline + num_read;
  226.     if((num_read < BlockSize) && buffer[end-1] != '\n') buffer[end] = '\n';
  227.     if(FIRST_TIME) {         /* if first time in the loop add a newline */
  228.         buffer[i-1] = '\n';  /* in front the  text.  */
  229.     i--;
  230.         FIRST_TIME = 0;
  231.     }
  232.     while (i < end )
  233.     {
  234.         c = buffer[i];
  235.         CMask = Mask[c];
  236.         if(c !=  Newline)
  237.         {
  238.            if(CMask != 0) {  
  239.               r2 = B[0];
  240.               r1 = Init1 & r2;
  241.               A[0] = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) | r1;
  242.               r3 = B[1];
  243.               r1 = Init1 & r3;
  244.               r0 = r2 | A[0];     /* A[0] | B[0] */
  245.               A[1] = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) |                                       (( r2 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  246.                      if(D == 1) goto Nextchar;
  247.               r2 = B[2];
  248.               r1 = Init1 & r2;
  249.               r0 = r3 | A[1];
  250.               A[2] = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) |                                       ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  251.                      if(D == 2) goto Nextchar;
  252.               r3 = B[3];
  253.               r1 = Init1 & r3;
  254.               r0 = r2 | A[2];
  255.               A[3] = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) |                                       ((r2 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  256.                      if(D == 3) goto Nextchar;
  257.               r2 = B[4];
  258.               r1 = Init1 & r2;
  259.               r0 = r3 | A[3];
  260.               A[4] = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) |                                        ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  261.                      if(D == 4)  goto Nextchar;
  262.            }  /* if(CMask) */
  263.        else  {
  264.               r2 = B[0];
  265.               A[0] = r2 & Init1; 
  266.               r3 = B[1];
  267.               r1 = Init1 & r3;
  268.               r0 = r2 | A[0];
  269.               A[1] = ((r2 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  270.                    if(D == 1) goto Nextchar;
  271.               r2 = B[2];
  272.               r1 = Init1 & r2;
  273.               r0 = r3 | A[1];
  274.               A[2] = ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  275.                    if(D == 2) goto Nextchar;
  276.               r3 = B[3];
  277.               r1 = Init1 & r3;
  278.               r0 = r2 | A[2];
  279.               A[3] = ((r2 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  280.                    if(D == 3) goto Nextchar;
  281.               r2 = B[4];
  282.               r1 = Init1 & r2;
  283.               r0 = r3 | A[3];
  284.               A[4] = ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  285.                    if(D == 4) goto Nextchar;
  286.            }
  287.         }
  288.         else {  j++;
  289.               r1 = Init1 & B[D];            /* match against endofline */
  290.               A[D] = ((Next[B[D]>>hh] | Next1[B[D]&LL]) & CMask) | r1;
  291.               if(TAIL) A[D] = ( Next[A[D]>>hh] | Next1[A[D]&LL] ) | A[D]; 
  292.                                            /* epsilon move */
  293.               if(( A[D] & 1 ) ^ INVERSE) {
  294.                    if(FILENAMEONLY) {
  295.                           num_of_matched++;
  296.                           printf("%s\n", CurrentFileName);
  297.                           return;
  298.                    } 
  299.                    r_output(buffer, i, end, j);
  300.               }
  301.               for(k=0; k<=D; k++)  B[k] = Init[0];
  302.               r1 = Init1 & B[0];
  303.               A[0] = (( Next[B[0]>>hh] | Next1[B[0]&LL]) & CMask) | r1;
  304.               for(k=1; k<=D; k++) {
  305.                    r3 = B[k];
  306.                    r1 = Init1 & r3;
  307.                    r2 = A[k-1] | B[k-1];
  308.                    A[k] = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) |                                       ((B[k-1] | Next[r2>>hh] | Next1[r2&LL]) & r_NO_ERR) | r1;
  309.               }
  310.         }
  311. Nextchar: i=i+1;
  312.         c = buffer[i];
  313.         CMask = Mask[c];
  314.         if(c != Newline)
  315.         {
  316.            if(CMask != 0) {  
  317.               r2 = A[0];
  318.               r1 = Init1 & r2;
  319.               B[0] = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) | r1;
  320.               r3 = A[1];
  321.               r1 = Init1 & r3;
  322.               r0 = B[0] | r2;
  323.               B[1] = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) |                                       ((r2 | Next[r0>>hh] | Next1[r0&LL]) & r_NO_ERR) | r1 ;  
  324.                      if(D == 1) goto Nextchar1;
  325.               r2 = A[2];
  326.               r1 = Init1 & r2;
  327.               r0 = B[1] | r3;
  328.               B[2] = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) |                                   ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  329.                      if(D == 2) goto Nextchar1;
  330.               r3 = A[3];
  331.               r1 = Init1 & r3;
  332.               r0 = B[2] | r2;
  333.               B[3] = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) |                                       ((r2 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  334.                      if(D == 3) goto Nextchar1;
  335.               r2 = A[4];
  336.               r1 = Init1 & r2;
  337.               r0 = B[3] | r3;
  338.               B[4] = ((Next[r2>>hh] | Next1[r2&LL]) & CMask) |                                       ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  339.                      if(D == 4)   goto Nextchar1;
  340.            }  /* if(CMask) */
  341.        else  {
  342.               r2 = A[0];
  343.               B[0] = r2 & Init1; 
  344.               r3 = A[1];
  345.               r1 = Init1 & r3;
  346.               r0 = B[0] | r2;
  347.               B[1] = ((r2 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  348.                    if(D == 1) goto Nextchar1;
  349.               r2 = A[2];
  350.               r1 = Init1 & r2;
  351.               r0 = B[1] | r3;
  352.               B[2] = ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  353.                    if(D == 2) goto Nextchar1;
  354.               r3 = A[3];
  355.               r1 = Init1 & r3;
  356.               r0 = B[2] | r2;
  357.               B[3] = ((r2 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  358.                    if(D == 3) goto Nextchar1;
  359.               r2 = A[4];
  360.               r1 = Init1 & r2;
  361.               r0 = B[3] | r3;
  362.               B[4] = ((r3 | Next[r0>>hh] | Next1[r0&LL])&r_NO_ERR) | r1 ;  
  363.                    if(D == 4) goto Nextchar1;
  364.            }
  365.         } /* if(NOT Newline) */
  366.         else {  j++;
  367.               r1 = Init1 & A[D];            /* match against endofline */
  368.               B[D] = ((Next[A[D]>>hh] | Next1[A[D]&LL]) & CMask) | r1;
  369.               if(TAIL) B[D] = ( Next[B[D]>>hh] | Next1[B[D]&LL] ) | B[D]; 
  370.                                            /* epsilon move */
  371.               if(( B[D] & 1 ) ^ INVERSE) {
  372.                    if(FILENAMEONLY) {
  373.                           num_of_matched++;
  374.                           printf("%s\n", CurrentFileName);
  375.                           return;
  376.                    } 
  377.                    r_output(buffer, i, end, j);
  378.               }
  379.               for(k=0; k<=D; k++) A[k] = Init0; 
  380.               r1 = Init1 & A[0];
  381.               B[0] = ((Next[A[0]>>hh] | Next1[A[0]&LL]) & CMask) | r1;
  382.               for(k=1; k<=D; k++) {
  383.                    r3 = A[k];
  384.                    r1 = Init1 & r3;
  385.                    r2 = A[k-1] | B[k-1];
  386.                    B[k] = ((Next[r3>>hh] | Next1[r3&LL]) & CMask) |                                       ((A[k-1] | Next[r2>>hh] | Next1[r2&LL]) & r_NO_ERR) | r1;
  387.               }
  388.         }
  389. Nextchar1: i=i+1;
  390.     } /* while */
  391.     strncpy(buffer, buffer+num_read, Maxline);
  392.   } /* while */
  393.   return;
  394. } /* re1 */
  395.  
  396. re(Text, M, D)
  397. int Text, M, D;
  398. {
  399.   register unsigned i, c, r1, r2, r3, CMask, k, Newline, Init0, Init1, end; 
  400.   register unsigned r_even, r_odd, r_NO_ERR ;
  401.   unsigned RMask[MAXSYM];
  402.   unsigned A[MaxRerror+1], B[MaxRerror+1];
  403.   int num_read, j=0, bp, lasti, base, ResidueSize; 
  404.   int FIRST_TIME; /* Flag */ 
  405.   base = WORD - M;
  406.   k = 2*exponen(M);
  407.   if(FIRST_IN_RE) {
  408.          compute_next(M, Next, Next1); 
  409.          FIRST_IN_RE = 0;    }
  410.   for(i=0; i< MAXSYM; i++) RMask[i] = Mask[i];
  411.   r_NO_ERR = NO_ERR_MASK;
  412.   Newline = '\n';
  413.   lasti = Maxline;
  414.   Init0 = Init[0] = Bit[base];
  415.   if(HEAD) Init0  = Init[0] = Init0 | Bit[base+1] ;
  416.   for(i=1; i<= D; i++) Init[i] = Init[i-1] | Next[Init[i-1]]; /* can be out? */
  417.   Init1 = Init0 | 1; 
  418.   r2 = r3 = Init0;
  419.   for(k=0; k<= D; k++) { A[k] = B[k] = Init[0]; }  /* can be out? */
  420.   FIRST_TIME = ON;
  421.   if ( D == 0 )
  422.   {
  423.     while ((num_read = read(Text, buffer + Maxline, BlockSize)) > 0)
  424.     {
  425.       i=Maxline; end = Maxline + num_read ;
  426.       if((num_read < BlockSize)&&buffer[end-1] != '\n') buffer[end] = '\n';
  427.       if(FIRST_TIME) {
  428.          buffer[i-1] = '\n';
  429.      i--;
  430.          FIRST_TIME = 0;
  431.       }
  432.       while (i < end) 
  433.       {              
  434.         c = buffer[i++];
  435.         CMask = RMask[c];
  436.         if(c != Newline)
  437.         {  
  438.               r1 = Init1 & r3;
  439.               r2 = (Next[r3] & CMask) | r1;
  440.         }
  441.         else {  
  442.               r1 = Init1 & r3;            /* match against '\n' */
  443.               r2 = Next[r3] & CMask | r1;
  444.               j++;
  445.               if(TAIL) r2 = Next[r2] | r2 ;   /* epsilon move */
  446.               if(( r2 & 1) ^ INVERSE) {
  447.                    if(FILENAMEONLY) {
  448.                           num_of_matched++;
  449.                           printf("%s\n", CurrentFileName);
  450.                           return;
  451.                    } 
  452.                    r_output(buffer, i-1, end, j);
  453.               }
  454.               lasti = i - 1;
  455.               r3 = Init0;
  456.               r2 = (Next[r3] & CMask) | Init0;
  457.         }
  458.         c = buffer[i++];   
  459.         CMask = RMask[c];
  460.         if(c != Newline)
  461.         {
  462.               r1 = Init1 & r2;
  463.               r3 = (Next[r2] & CMask) | r1;
  464.         }
  465.         else {  j++;
  466.               r1 = Init1 & r2;            /* match against endofline */
  467.               r3 = Next[r2] & CMask | r1;
  468.               if(TAIL) r3 = Next[r3] | r3;
  469.               if(( r3 & 1) ^ INVERSE) {
  470.                    if(FILENAMEONLY) {
  471.                           num_of_matched++;
  472.                           printf("%s\n", CurrentFileName);
  473.                           return;
  474.                    } 
  475.                    r_output(buffer, i-1, end, j);
  476.               }
  477.               lasti = i - 1;
  478.               r2 = Init0; 
  479.               r3 = (Next[r2] & CMask) | Init0;  /* match the newline */
  480.         }
  481.       } /* while */
  482.       ResidueSize = Maxline + num_read - lasti;
  483.       if(ResidueSize > Maxline) {
  484.            ResidueSize = Maxline;  }
  485.       strncpy(buffer+Maxline-ResidueSize, buffer+lasti, ResidueSize);
  486.       lasti = Maxline - ResidueSize;
  487.     } /* while */
  488.   return;
  489.   } /* end if(D==0) */
  490.   while ((num_read = read(Text, buffer + Maxline, BlockSize)) > 0)
  491.   {
  492.     i=Maxline; end = Maxline+num_read;
  493.     if((num_read < BlockSize) && buffer[end-1] != '\n') buffer[end] = '\n';
  494.     if(FIRST_TIME) {
  495.         buffer[i-1] = '\n';
  496.     i--;
  497.         FIRST_TIME = 0;
  498.     }
  499.     while (i < end)
  500.     {   c = buffer[i++];
  501.         CMask = RMask[c];
  502.         if (c != Newline)
  503.         {  
  504.               r_even = B[0];
  505.               r1 = Init1 & r_even;
  506.               A[0] = (Next[r_even] & CMask) | r1;
  507.               r_odd = B[1];
  508.               r1 = Init1 & r_odd;
  509.               r2 = (r_even | Next[r_even|A[0]]) &r_NO_ERR;
  510.               A[1] = (Next[r_odd] & CMask) | r2 | r1 ;  
  511.                      if(D == 1) goto Nextchar;
  512.               r_even = B[2];
  513.               r1 = Init1 & r_even;
  514.               r2 = (r_odd | Next[r_odd|A[1]]) &r_NO_ERR;
  515.               A[2] = (Next[r_even] & CMask) | r2 | r1 ;  
  516.                      if(D == 2) goto Nextchar;
  517.               r_odd = B[3];
  518.               r1 = Init1 & r_odd;
  519.               r2 = (r_even | Next[r_even|A[2]]) &r_NO_ERR;
  520.               A[3] = (Next[r_odd] & CMask) | r2 | r1 ;  
  521.                      if(D == 3) goto Nextchar;
  522.               r_even = B[4];
  523.               r1 = Init1 & r_even;
  524.               r2 = (r_odd | Next[r_odd|A[3]]) &r_NO_ERR;
  525.               A[4] = (Next[r_even] & CMask) | r2 | r1 ;  
  526.               goto Nextchar;
  527.         } /* if NOT Newline */
  528.         else {  j++;
  529.               r1 = Init1 & B[D];               /* match endofline */
  530.               A[D] = (Next[B[D]] & CMask) | r1;
  531.               if(TAIL) A[D] = Next[A[D]] | A[D];
  532.               if((A[D] & 1) ^ INVERSE )  {
  533.                    if(FILENAMEONLY) {
  534.                           num_of_matched++;    
  535.                           printf("%s\n", CurrentFileName);
  536.                           return;
  537.                    }  
  538.                    r_output(buffer, i-1, end, j);
  539.               }
  540.               for(k=0; k<= D; k++) { A[k] = B[k] = Init[k]; }
  541.               r1 = Init1 & B[0]; 
  542.               A[0] = (Next[B[0]] & CMask) | r1;
  543.               for(k=1; k<= D; k++) {
  544.                     r1 = Init1 & B[k];
  545.                     r2 = (B[k-1] | Next[A[k-1]|B[k-1]]) &r_NO_ERR;
  546.                     A[k] = (Next[B[k]] & CMask) | r1 | r2;
  547.               }
  548.         }
  549. Nextchar: 
  550.         c = buffer[i];
  551.         CMask = RMask[c];
  552.         if(c != Newline)
  553.         { 
  554.               r1 = Init1 & A[0];
  555.               B[0] = (Next[A[0]] & CMask) | r1;
  556.               r1 = Init1 & A[1];
  557.               B[1] = (Next[A[1]] & CMask) |                                                          ((A[0] | Next[A[0] | B[0]]) & r_NO_ERR) | r1 ;  
  558.                      if(D == 1) goto Nextchar1;
  559.               r1 = Init1 & A[2];
  560.               B[2] = (Next[A[2]] & CMask) | ((A[1] | Next[A[1] | B[1]]) &r_NO_ERR) | r1 ;  
  561.                      if(D == 2) goto Nextchar1;
  562.               r1 = Init1 & A[3];
  563.               B[3] = (Next[A[3]] & CMask) | ((A[2] | Next[A[2] | B[2]])&r_NO_ERR) | r1 ;  
  564.                      if(D == 3) goto Nextchar1;
  565.               r1 = Init1 & A[4];
  566.               B[4] = (Next[A[4]] & CMask) | ((A[3] | Next[A[3] | B[3]])&r_NO_ERR) | r1 ;  
  567.               goto Nextchar1;
  568.         } /* if(NOT Newline) */
  569.         else {  j++;
  570.               r1 = Init1 & A[D];               /* match endofline */
  571.               B[D] = (Next[A[D]] & CMask) | r1;
  572.               if(TAIL) B[D] = Next[B[D]] | B[D];
  573.               if((B[D] & 1) ^ INVERSE )  {
  574.                    if(FILENAMEONLY) {
  575.                           num_of_matched++;
  576.                           printf("%s\n", CurrentFileName);
  577.                           return;
  578.                    } 
  579.                    r_output(buffer, i, end, j);
  580.               }
  581.               for(k=0; k<= D; k++) { A[k] = B[k] = Init[k]; }
  582.               r1 = Init1 & A[0]; 
  583.               B[0] = (Next[A[0]] & CMask) | r1;
  584.               for(k=1; k<= D; k++) {
  585.                     r1 = Init1 & A[k];
  586.                     r2 = (A[k-1] | Next[A[k-1]|B[k-1]])&r_NO_ERR;
  587.                     B[k] = (Next[A[k]] & CMask) | r1 | r2;
  588.               }
  589.         }
  590. Nextchar1: i++;
  591.     } /* while i < end */
  592.     strncpy(buffer, buffer+num_read, Maxline);
  593.   } /* while  read() */
  594.   return;
  595. } /* re */
  596.  
  597.  
  598. r_output (buffer, i, end, j) 
  599. int i, end, j; 
  600. CHAR *buffer;
  601. {
  602. int bp;
  603.       if(i >= end) return;
  604.       num_of_matched++;
  605.       if(COUNT)  return; 
  606.       if(FNAME) printf("%s: ", CurrentFileName);
  607.       bp = i-1;
  608.       while ((buffer[bp] != '\n') && (bp > 0)) bp--;
  609.       if(LINENUM) printf("%d: ", j); 
  610.       if(buffer[bp] != '\n') bp = Maxline-1;
  611.       bp++; 
  612.       while (bp <= i ) putchar(buffer[bp++]);
  613. }
  614.  
  615. main(argc, argv)
  616. int argc; char *argv[];
  617. {
  618.   int N, M, D=0, fp, fd, i, j; 
  619.   char c;
  620.   int filetype;
  621.   unsigned char Pattern[MAXPAT], OldPattern[MAXPAT], temp[MAXPAT];
  622.   
  623.   initial_value();
  624.   strcpy(Progname, argv[0]);
  625.   if (argc < 2) usage();
  626.   Pattern[0] = '\0';
  627.   while(--argc > 0 && (*++argv)[0] == '-') {
  628.      c = *(argv[0]+1); 
  629.      switch(c) {
  630.        case 'c' : COUNT = ON;    /* output the # of matched */
  631.                   break;
  632.        case 's' : SILENT = ON;   /* silent mode  */
  633.                   break;
  634.        case 'p' : I = 0;         /* insertion cost is 0 */
  635.                   break; 
  636.        case 'x' : WHOLELINE = ON;  /* match the whole line */
  637.           if(WORDBOUND) {
  638.             fprintf(stderr, "%s: illegal option combination\n", Progname);
  639.             exit(2);
  640.           }
  641.                   break;
  642.        case 'L' : break;
  643.        case 'd' : DELIMITER = ON;  /* user defines delimiter */
  644.                   if(argc <= 1) usage();
  645.                   if (argv[0][2] == '\0') {/* space after -d option */
  646.                     argv++;
  647.                     if ((D_length = strlen(argv[0])) > MaxDelimit) {
  648.                       fprintf(stderr, "%s: delimiter pattern too long\n", Progname);
  649.                       exit(2);
  650.                     }
  651.                     D_pattern[0] = '<';
  652.                     strcpy(D_pattern+1, argv[0]);
  653.                     argc--;
  654.                   } else {
  655.                     if ((D_length = strlen(argv[0]+2)) > MaxDelimit) {
  656.                       fprintf(stderr, "%s: delimiter pattern too long\n", Progname);
  657.                       exit(2);
  658.                     }
  659.                     D_pattern[0] = '<';
  660.                     strcpy(D_pattern+1, argv[0]+2);
  661.                   } /* else */
  662.                   strcat(D_pattern, ">; ");
  663.                   D_length++;   /* to count ';' as one */
  664.                   break;
  665.        case 'e' : argc--;
  666.           if(argc == 0) {
  667.             fprintf(stderr, "%s: the pattern should immediately follow the -e option\n", Progname);
  668.             usage();
  669.           }
  670.           if((++argv)[0][0] == '-') {
  671.                        Pattern[0] = '\\';
  672.                        strcat(Pattern, (argv)[0]);
  673.                   }
  674.                   else strcat(Pattern, argv[0]);
  675.                   break;
  676.        case 'f' : PAT_FILE = ON;
  677.           argv++;
  678.           argc--;
  679.           if((fp = open(argv[0], 0)) < 0) {
  680.             fprintf(stderr, "%s: Can't open pattern file %s\n", Progname, argv[0]);
  681.             exit(2);
  682.           }
  683.           break;
  684.        case 'h' : NOFILENAME = ON;
  685.                   break;
  686.        case 'i' : NOUPPER = ON;
  687.                   break;
  688.        case 'k' : argc--;
  689.           if(argc == 0) {
  690.             fprintf(stderr, "%s: the pattern should immediately follow the -k option\n", Progname);
  691.             usage();
  692.           }
  693.           CONSTANT = ON;
  694.           argv++;
  695.           strcat(Pattern, argv[0]);
  696.           if(argc > 1 && argv[1][0] == '-') {
  697.             fprintf(stderr, "%s: -k should be the last option in the command\n", Progname);
  698.             exit(2);
  699.           }
  700.           break;
  701.        case 'l' : FILENAMEONLY = ON;
  702.                   break;
  703.        case 'n' : LINENUM = ON;  /* output prefixed by line no*/
  704.                   break;
  705.        case 'v' : INVERSE = ON;  /* output no-matched lines */
  706.                   break;
  707.        case 't' : OUTTAIL = ON;  /* output from tail of delimiter */
  708.                   break;
  709.        case 'B' : BESTMATCH = ON;
  710.                   break;
  711.        case 'w' : WORDBOUND = ON;/* match to words */
  712.           if(WHOLELINE) {
  713.             fprintf(stderr, "%s: illegal option combination\n", Progname);
  714.             exit(2);
  715.           }
  716.                   break;
  717.        case 'y' : NOPROMPT = ON;
  718.           break;
  719.        case 'I' : I = atoi(argv[0]+2);  /* Insertion Cost */
  720.               JUMP = ON;
  721.                   break;
  722.        case 'S' : S = atoi(argv[0]+2);  /* Substitution Cost */
  723.                   JUMP = ON;
  724.                   break;
  725.        case 'D' : DD = atoi(argv[0]+2); /* Deletion Cost */
  726.                   JUMP = ON;
  727.                   break;
  728.        case 'G' : FILEOUT = ON; 
  729.           COUNT = ON;
  730.           break;
  731.        default  : if (isdigit(c)) {
  732.             APPROX = ON;
  733.                     D = atoi(argv[0]+1);
  734.                     if (D > MaxError) {
  735.                       fprintf(stderr,"%s: the maximum number of errors is %d \n", Progname, MaxError);
  736.                       exit(2);
  737.                     }
  738.                   } else {
  739.                     fprintf(stderr, "%s: illegal option  -%c\n",Progname, c);
  740.             usage();
  741.                   }
  742.        } /* switch(c) */
  743.   } /* while (--argc > 0 && (*++argv)[0] == '-') */
  744.  
  745.   if (FILENAMEONLY && NOFILENAME) {
  746.     fprintf(stderr, "%s: -h and -l options are mutually exclusive\n",Progname);
  747.   }
  748.   if (COUNT && (FILENAMEONLY || NOFILENAME)) {
  749.       FILENAMEONLY = OFF; 
  750.       if(!FILEOUT) NOFILENAME = OFF;
  751.   }
  752.   if (!(PAT_FILE) && Pattern[0] == '\0') { /* Pattern not set with -e option */
  753.     if (argc == 0) usage();
  754.     strcpy(Pattern, *argv); 
  755.     argc--;
  756.     argv++;
  757.   }
  758.   Numfiles = 0;  
  759.   fd = 3; /* make sure it's not 0 */
  760.   if (argc == 0)  /* check Pattern against stdin */
  761.     fd = 0;
  762.   else {
  763.     if (!(Textfiles = (CHAR **)malloc(argc * sizeof(CHAR *) ))) {
  764.       fprintf(stderr, "%s: malloc failure (you probably don't have enough memory)\n", Progname);
  765.       exit(2);
  766.     }
  767.     while (argc--)  { /* one or more filenames on command line -- put
  768.                           the valid filenames in a array of strings */    
  769. /*
  770.       if ((filetype = check_file(*argv)) != ISASCIIFILE) {
  771.     if(filetype == NOSUCHFILE) fprintf(stderr,"%s: %s: no such file or directory\n",Progname,*argv);
  772.         argv++;
  773. */
  774.       
  775.       if ((filetype = check_file(*argv)) == NOSUCHFILE) {
  776.     if(filetype == NOSUCHFILE) fprintf(stderr,"%s: %s: no such file or directory\n",Progname,*argv);
  777.         argv++;
  778.       } else { /* file is ascii*/
  779.         if (!(Textfiles[Numfiles] = (CHAR *)malloc((strlen(*argv)+1)))) {
  780.           fprintf(stderr, "%s: malloc failure (you probably don't have enough memory)\n", Progname);
  781.           exit(2);
  782.         }
  783.         strcpy(Textfiles[Numfiles++], *argv++);
  784.        } /* else */
  785.      } /* while (argc--) */
  786.   } /* else */
  787.   checksg(Pattern, D);       /* check if the pattern is simple */
  788.   strcpy(OldPattern, Pattern);
  789.   if (SGREP == 0) {
  790.       preprocess(D_pattern, Pattern);
  791.       strcpy(old_D_pat, D_pattern);
  792.       M = maskgen(Pattern, D);
  793.   }
  794.   else M = strlen(OldPattern);
  795.   if (PAT_FILE)  prepf(fp);
  796.   if (Numfiles > 1) FNAME = ON;
  797.   if (NOFILENAME) FNAME = 0;
  798.   num_of_matched = 0;
  799.   compat(); /* check compatibility between options */
  800.   if (fd == 0) {
  801.     if(FILENAMEONLY) {
  802.        fprintf(stderr, "%s: -l option is not compatible with standard input\n", Progname);
  803.        exit(2);  
  804.     }
  805.     if(PAT_FILE) mgrep(fd);
  806.     else {
  807.         if(SGREP) sgrep(OldPattern, strlen(OldPattern), fd, D);
  808.        else      bitap(old_D_pat, Pattern, fd, M, D);
  809.     }
  810.     if (COUNT) {
  811.     if(INVERSE && PAT_FILE) printf("%d\n", total_line-num_of_matched);
  812.     else printf("%d\n", num_of_matched);
  813.     }
  814.   } 
  815.   else {
  816.     for (i = 0; i < Numfiles; i++, close(fd), num_of_matched = 0) {
  817.           strcpy(CurrentFileName, Textfiles[i]);
  818.           if ((fd = open(Textfiles[i], 0)) <= 0) {
  819.             fprintf(stderr, "%s: can't open file %s\n",Progname, Textfiles[i]);
  820.           } 
  821.     else { 
  822.              if(PAT_FILE) mgrep(fd);
  823.              else {
  824.                      if(SGREP) sgrep(OldPattern, strlen(OldPattern), fd, D);
  825.                      else      bitap(old_D_pat, Pattern, fd, M, D);
  826.             }
  827.             if (num_of_matched) NOMATCH = OFF;
  828.             if (COUNT && !FILEOUT) {
  829.             if(INVERSE && PAT_FILE) {
  830.                      if(FNAME) printf("%s: %d\n", CurrentFileName, total_line - num_of_matched);
  831.                 else printf("%d\n", total_line - num_of_matched);
  832.             }
  833.             else {
  834.                      if(FNAME) printf("%s: %d\n", CurrentFileName, num_of_matched);
  835.                 else printf("%d\n", num_of_matched);
  836.             }
  837.             }  /* if COUNT */
  838.         if(FILEOUT && num_of_matched) {
  839.             file_out(CurrentFileName);
  840.         }
  841.           } /* else */
  842.     }  /* for i < Numfiles */
  843.     if(NOMATCH && BESTMATCH) {
  844.     if(WORDBOUND || WHOLELINE || LINENUM || INVERSE) { 
  845.         SGREP = 0;    
  846.               preprocess(D_pattern, Pattern);
  847.               strcpy(old_D_pat, D_pattern);
  848.               M = maskgen(Pattern, D);
  849.     }
  850.     COUNT=ON; D=1;
  851.     while(D<M && D<=MaxError && num_of_matched == 0) {
  852.             for (i = 0; i < Numfiles; i++, close(fd)) {
  853.                   strcpy(CurrentFileName, Textfiles[i]);
  854.                   if ((fd = open(Textfiles[i], 0)) > 0) {
  855.                      if(PAT_FILE) mgrep(fd);
  856.                      else {
  857.                                  if(SGREP) sgrep(OldPattern,strlen(OldPattern),fd,D);
  858.                                  else bitap(old_D_pat,Pattern,fd,M,D);
  859.                       }
  860.             } 
  861.            }  /* for i < Numfiles */
  862.         D++;
  863.     } /* while */
  864.     if(num_of_matched > 0) {
  865.         D--; COUNT = 0;
  866.         if(NOPROMPT) goto GO_AHEAD;
  867.         if(D==1) fprintf(stderr, "best match has 1 error, ");
  868.         else fprintf(stderr, "best match has %d errors, ", D);
  869.         fflush(stderr);
  870.         if(num_of_matched == 1) fprintf(stderr,"there is 1 match, output it? (y/n)");
  871.         else fprintf(stderr,"there are %d matches, output them? (y/n)", num_of_matched);
  872.         scanf("%c",&c);
  873.         if(c != 'y') goto CONT;
  874. GO_AHEAD:
  875.             for (i = 0; i < Numfiles; i++, close(fd)) {
  876.                   strcpy(CurrentFileName, Textfiles[i]);
  877.                   if ((fd = open(Textfiles[i], 0)) > 0) {
  878.                      if(PAT_FILE) mgrep(fd);
  879.                      else {
  880.                                  if(SGREP) sgrep(OldPattern,strlen(OldPattern),fd,D);
  881.                                  else bitap(old_D_pat,Pattern,fd,M,D);
  882.                 }
  883.                   } 
  884.            }  /* for i < Numfiles */
  885.         NOMATCH = 0;
  886.     }
  887.    }
  888.  }
  889. CONT:
  890.  if(EATFIRST) {
  891.       printf("\n");
  892.       EATFIRST = OFF;
  893.  }
  894.  if(num_of_matched) NOMATCH = OFF;
  895.  if(NOMATCH) exit(1);
  896.  exit(0);
  897. } /* end of main() */
  898.  
  899.        
  900. file_out(fname)
  901. char *fname;
  902. {
  903. int num_read;
  904. int fd;
  905. int i, len;
  906. CHAR buf[4097];
  907.     if(FNAME) {
  908.         len = strlen(fname);
  909.         putchar('\n');
  910.         for(i=0; i< len; i++) putchar(':');
  911.         putchar('\n');
  912.         printf("%s\n", CurrentFileName);
  913.         len = strlen(fname);
  914.         for(i=0; i< len; i++) putchar(':');
  915.         putchar('\n');
  916.         fflush(stdout);
  917.     }
  918.     fd = open(fname, 0);
  919.     while((num_read = read(fd, buf, 4096)) > 0) 
  920.         write(1, buf, num_read);
  921. }
  922.  
  923.  
  924. usage()
  925. {
  926.         fprintf(stderr, "usage: %s [-#cdehiklnpstvwxBDGIS] [-f patternfile] pattern [files]\n", Progname); 
  927.      printf("\n");    
  928.     fprintf(stderr, "summary of frequently used options:\n");
  929.     fprintf(stderr, "-#: find matches with at most # errors\n");
  930.     fprintf(stderr, "-c: output the number of matched records\n");
  931.     fprintf(stderr, "-d: define record delimiter\n");
  932.     fprintf(stderr, "-h: do not output file names\n");
  933.     fprintf(stderr, "-i: case-insensitive search, e.g., 'a' = 'A'\n");
  934.     fprintf(stderr, "-l: output the names of files that contain a match\n");
  935.     fprintf(stderr, "-n: output record prefixed by record number\n");
  936.     fprintf(stderr, "-v: output those records containing no matches\n");
  937.     fprintf(stderr, "-w: pattern has to match as a word, e.g., 'win' will not match 'wind'\n");
  938.     fprintf(stderr, "-B: best match mode. find the closest matches to the pattern\n"); 
  939.     fprintf(stderr, "-G: output the files that contain a match\n");
  940.      printf("\n");    
  941.  
  942.         exit(2);
  943. }
  944.  
  945. checksg(Pattern, D) 
  946. CHAR *Pattern; int D;
  947. {                          
  948.   char c;
  949.   int i, m;
  950.   m = strlen(Pattern);
  951.   if(!(PAT_FILE) && m <= D) {
  952.       fprintf(stderr, "%s: size of pattern must be greater than number of errors\n", Progname);
  953.       exit(2);
  954.   }
  955.   SIMPLEPATTERN = ON;
  956.   for (i=0; i < m; i++) 
  957.   {
  958.       switch(Pattern[i])
  959.       {
  960.          case ';' : SIMPLEPATTERN = OFF; break;
  961.          case ',' : SIMPLEPATTERN = OFF; break;
  962.          case '.' : SIMPLEPATTERN = OFF; break;
  963.          case '*' : SIMPLEPATTERN = OFF; break;
  964.          case '-' : SIMPLEPATTERN = OFF; break;
  965.          case '[' : SIMPLEPATTERN = OFF; break;
  966.          case ']' : SIMPLEPATTERN = OFF; break;
  967.          case '(' : SIMPLEPATTERN = OFF; break;
  968.          case ')' : SIMPLEPATTERN = OFF; break;
  969.          case '<' : SIMPLEPATTERN = OFF; break;
  970.          case '>' : SIMPLEPATTERN = OFF; break;
  971.          case '^' : if(D > 0) SIMPLEPATTERN = OFF; 
  972.             break;
  973.          case '$' : if(D > 0) SIMPLEPATTERN = OFF; 
  974.             break;
  975.          case '|' : SIMPLEPATTERN = OFF; break;
  976.          case '#' : SIMPLEPATTERN = OFF; break;
  977.          case '\\' : SIMPLEPATTERN = OFF; break;
  978.          default  : break;
  979.       }
  980.   }
  981.   if (CONSTANT) SIMPLEPATTERN = ON;
  982.   if (SIMPLEPATTERN == OFF) return;
  983.   if (NOUPPER && D) return;     
  984.   if (JUMP == ON) return;
  985.   if (I == 0) return;
  986.   if (LINENUM) return;
  987.   if (DELIMITER) return;   
  988.   if (INVERSE) return;
  989.   if (WORDBOUND && D > 0) return;  
  990.   if (WHOLELINE && D > 0) return;  
  991.   if (SILENT) return;     /* REMINDER: to be removed */
  992.   SGREP = ON;
  993.   if(m >= 16) DNA = ON;
  994.   for(i=0; i<m; i++) {
  995.     c = Pattern[i];
  996.     if(c == 'a' || c == 'c' || c == 't' || c == 'g' ) ;
  997.     else DNA = OFF;
  998.   }
  999.   return;
  1000. }
  1001.  
  1002. output (buffer, i1, i2, j)  
  1003. register CHAR *buffer; int i1, i2, j;
  1004. {
  1005. register CHAR *bp, *outend;
  1006.     if(i1 > i2) return;
  1007.         num_of_matched++;
  1008.         if(COUNT)  return;
  1009.         if(SILENT) return;
  1010.     if(OUTTAIL) {
  1011.               i1 = i1 + D_length;
  1012.               i2 = i2 + D_length;
  1013.         }
  1014.         if(DELIMITER) j = j+1;
  1015.         if(FIRSTOUTPUT) {
  1016.            if (buffer[i1] == '\n')  {
  1017.                i1++;
  1018.                EATFIRST = ON;
  1019.            }
  1020.            FIRSTOUTPUT = 0;
  1021.         }
  1022.         if(TRUNCATE) {
  1023.            fprintf(stderr, "WARNING!!!  some lines have been truncated in output record #%d\n", num_of_matched-1);
  1024.         }
  1025.         while(buffer[i1] == '\n' && i1 <= i2) {
  1026.        printf("\n");
  1027.            i1++;
  1028.         }
  1029.         if(FNAME == ON) printf("%s: ", CurrentFileName);
  1030.         if(LINENUM) printf("%d: ", j-1); 
  1031.     bp = buffer + i1;
  1032.     outend = buffer + i2;
  1033.     while(bp <= outend) putchar(*bp++);
  1034. }
  1035.  
  1036. /* end of main.c */
  1037.